#ifndef THREAD_MANAGER_H
#define THREAD_MANAGER_H

#include <chrono>
#include <mutex>
#include <thread>
#include "DataBuffer.hpp"
#include "DataType.hpp"
#include "Processor.h"
#include "TimeQueue.hpp"
#include "armor.hpp"
#include "easylogging++.h"
#include "tcp_logger.h"
#include "Camera.h"
#include "Compensator.h"
#include "Processor.h"
#include "Serialcodec.h"
#include "detector.hpp"


#define TIMEIT(CODE_BLOCK)                                                                                 \
    do {                                                                                                   \
        auto start = std::chrono::steady_clock::now();                                                     \
        CODE_BLOCK;                                                                                        \
        auto end = std::chrono::steady_clock::now();                                                       \
        auto diff = end - start;                                                                           \
        LOG(INFO) << "Time elapsed: " << std::chrono::duration<double, std::milli>(diff).count() << " ms"; \
    } while (0);

#define TIMEIT_ID(ID, CODE_BLOCK)                                                                                         \
    do {                                                                                                                  \
        auto start_##ID = std::chrono::steady_clock::now();                                                               \
        CODE_BLOCK;                                                                                                       \
        auto end_##ID = std::chrono::steady_clock::now();                                                                 \
        auto diff_##ID = end_##ID - start_##ID;                                                                           \
        LOG(INFO) << "Time elapsed (" #ID "): " << std::chrono::duration<double, std::milli>(diff_##ID).count() << " ms"; \
    } while (0);


namespace hnurm
{
    class ThreadManager
    {
    public:
        ThreadManager() = default;

        ~ThreadManager();

        explicit ThreadManager(const std::string &config_file_path);

        void InitManager(const std::string &config_file_path);

        [[noreturn]] void ImageAcquisitionThread();

        [[noreturn]] void ImageProcessingThread();

        [[noreturn]] void SerialRecvThread();

        [[noreturn]] void SerialSendThread();

        void Exit();

    public:
        std::thread::native_handle_type image_acq_id{};
        std::thread::native_handle_type image_proc_id{};
        std::thread::native_handle_type solve_id{};
        std::thread::native_handle_type serial_recv_id{};
        std::thread::native_handle_type serial_send_id{};

    private:
        std::unique_ptr<HKcam> _camera;
        std::unique_ptr<Detector> _detector;
        std::unique_ptr<Processor> _processor;
        std::unique_ptr<Compensator> _compensator;
        std::unique_ptr<SerialCodec> _serial_codec;
        std::unique_ptr<TCP_Logger> _tcp_logger;

        // config nodes from config.yaml
        cv::FileNode _serial_config_node;
        cv::FileNode _camera_config_node;
        //cv::FileNode _tracker_config_node;
        cv::FileNode _detector_config_node;
        cv::FileNode _processor_config_node;
        cv::FileNode _compensator_config_node;
        cv::FileNode _solver_config_node;

        // DataBuffer
        DataBuffer<ImgInfo> _image_buffer;
        TimeQueue<VisionRecvData> _recv_buffer;
        DataBuffer<VisionSendData> _send_buffer;
        DataBuffer<std::vector<Armor>> _armor_buffer;

        float hit;
        float miss;
    };
}// namespace hnurm

#endif// !THREAD_MANAGER_H